﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Navigation;

using System.Windows.Browser;
using System.Xml;

using PermDoc.Common;

namespace PermDoc
{

    // http://msdn.microsoft.com/en-us/magazine/dd943052.aspx

    public partial class PageDeepZoom : Page
    {

        #region Members

        private SubImageInfo[] _Metadata;

        Point lastMousePos = new Point();
        Point lastMouseLogicalPos = new Point();
        Point lastMouseViewPort = new Point();
        bool duringDrag = false;
        double zoom = 1;
        double minzoom = 0.001;
        bool duringOpen = false;

        #endregion

        #region Constructors
        public PageDeepZoom()
        {
            InitializeComponent();

            //WebClient wc = new WebClient();
            //wc.OpenReadCompleted += new
            //    OpenReadCompletedEventHandler(WebClient_OpenReadCompleted);
            //wc.OpenReadAsync(new Uri("http://sp.korablik.local:98/ws/SP/PermDocs_FilesInfo_ByDocSetID_DeepZoom.aspx?intid=353962", UriKind.Absolute));


            this.MouseMove += delegate(object sender, MouseEventArgs e)
            {
                this.lastMousePos = e.GetPosition(this.oDeepZoom);
            };

            new MouseWheelHelper(this).Moved += delegate(object sender, PermDoc.Common.MouseWheelEventArgs e)
            {
                double newzoom = zoom;
                if (e.Delta > 0)
                    newzoom /= 1.3;
                else
                    newzoom *= 1.3;
                Point logicalPoint = this.oDeepZoom.ElementToLogicalPoint(this.lastMousePos);

                this.oDeepZoom.ZoomAboutLogicalPoint(zoom / newzoom, logicalPoint.X, logicalPoint.Y);
                zoom = newzoom;
            };
        }
        #endregion

        #region Page Methods
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }
        private void Page_Loaded(object sender, RoutedEventArgs e)
        {

            if (App.SelectedDocumentTopic != null)
            {
                oBtnOpenDocInBrowser.IsEnabled = true;
                oBtnOpenDocInBrowser.NavigateUri =
                    new Uri(@"http://sp.korablik.local/shops/DocLib/"
                        + App.SelectedDocumentTopic.No, UriKind.Absolute);

                oTxtNo.DataContext = App.SelectedDocumentTopic;
                oTxtDocDate.DataContext = App.SelectedDocumentTopic;
                oTxtDocCreated.DataContext = App.SelectedDocumentTopic;
                oTxtDocAuthor.DataContext = App.SelectedDocumentTopic;
                oTxtDocModify.DataContext = App.SelectedDocumentTopic;
                oTxtDocEditor.DataContext = App.SelectedDocumentTopic;
                oTxtDocState.DataContext = App.SelectedDocumentTopic;
                oTxtDocShop.DataContext = App.SelectedDocumentTopic;
                oTxtDocKontr.DataContext = App.SelectedDocumentTopic;
                oTxtDocNo_Doc.DataContext = App.SelectedDocumentTopic;

                oDeepZoom.AllowDownloading = true;

                //oDeepZoom.Source = new MandelbrotTileSource((int)Math.Pow(2, 30), (int)Math.Pow(2, 30), 128, 128);
                oDeepZoom.Source = new MandelbrotTileSource(640, 640, 640, 640);

            }
            else
            {
                oBtnOpenDocInBrowser.IsEnabled = false;
            }

        }
        private void Page_Unloaded(object sender, RoutedEventArgs e)
        {
        }
        #endregion

        #region Controls Events
        private int GetSubImageIndex(Point point)
        {
            // Hit-test each sub-image in the MultiScaleImage control to determine
            // whether  "point " lies within a sub-image
            for (int i = oDeepZoom.SubImages.Count - 1; i >= 0; i--)
            {
                MultiScaleSubImage image = oDeepZoom.SubImages[i];
                double width = oDeepZoom.ActualWidth /
                    (oDeepZoom.ViewportWidth * image.ViewportWidth);
                double height = oDeepZoom.ActualWidth /
                    (oDeepZoom.ViewportWidth * image.ViewportWidth * image.AspectRatio);

                Point pos = oDeepZoom.LogicalToElementPoint(new Point(
                    -image.ViewportOrigin.X / image.ViewportWidth,
                    -image.ViewportOrigin.Y / image.ViewportWidth)
                );
                Rect rect = new Rect(pos.X, pos.Y, width, height);

                if (rect.Contains(point))
                {
                    // Return the image index
                    return i;
                }
            }
            // No corresponding sub-image
            return -1;
        }
        private void Home_Click(object sender, MouseButtonEventArgs e)
        {
            this.oDeepZoom.ViewportOrigin = new Point(0, 0);
            this.oDeepZoom.ViewportWidth = 1;
            zoom = 1;
        }
        private void ZoomIn_Click(object sender, MouseButtonEventArgs e)
        {
            double newzoom = zoom / 1.3;
            if (newzoom < minzoom) { newzoom = minzoom; }
            Point logicalPoint = this.oDeepZoom.ElementToLogicalPoint(new Point(this.ActualWidth / 2, this.ActualHeight / 2));
            this.oDeepZoom.ZoomAboutLogicalPoint(zoom / newzoom, logicalPoint.X, logicalPoint.Y);
            zoom = newzoom;
        }
        private void ZoomOut_Click(object sender, MouseButtonEventArgs e)
        {
            double newzoom = zoom * 1.3;
            if (newzoom > 1) { newzoom = 1; }
            Point logicalPoint = this.oDeepZoom.ElementToLogicalPoint(new Point(this.ActualWidth / 2, this.ActualHeight / 2));
            this.oDeepZoom.ZoomAboutLogicalPoint(zoom / newzoom, logicalPoint.X, logicalPoint.Y);
            zoom = newzoom;
        }
        private void oDeepZoom_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            lastMouseLogicalPos = e.GetPosition(this.oDeepZoom);
            lastMouseViewPort = this.oDeepZoom.ViewportOrigin;
            duringDrag = true;
        }
        private void oDeepZoom_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            duringDrag = false;
            this.oDeepZoom.UseSprings = true;
        }
        private void oDeepZoom_MouseMove(object sender, MouseEventArgs e)
        {
            if (duringDrag)
            {
                Point newPoint = lastMouseViewPort;
                Point thisMouseLogicalPos = e.GetPosition(this.oDeepZoom);
                newPoint.X += (lastMouseLogicalPos.X - thisMouseLogicalPos.X) / this.oDeepZoom.ActualWidth * this.oDeepZoom.ViewportWidth;
                newPoint.Y += (lastMouseLogicalPos.Y - thisMouseLogicalPos.Y) / this.oDeepZoom.ActualWidth * this.oDeepZoom.ViewportWidth;
                this.oDeepZoom.ViewportOrigin = newPoint;
            }
        }
        private void oDeepZoom_ImageOpenSucceeded(object sender, RoutedEventArgs e)
        {
            duringOpen = true;
        }
        private void oDeepZoom_MotionFinished(object sender, RoutedEventArgs e)
        {
            if (duringOpen)
            {
                duringOpen = false;

                // zoom out a tad bit.
                this.oDeepZoom.ViewportOrigin = new Point(-0.4, -0.1);
                this.oDeepZoom.ViewportWidth = 1.8;
            }
        }
        #endregion
        
        #region Data

        //private void WebClient_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
        //{

        //    if (e.Error != null)
        //    {
        //        MessageBox.Show("Unable to load XML metadata ");
        //        return;
        //    }

        //    // Create a collection of SubImageInfo objects from Metadata.xml
        //    List<SubImageInfo> images = new List<SubImageInfo>();

        //    try
        //    {
        //        XmlReader reader = XmlReader.Create(e.Result);
        //        SubImageInfo info = null;

        //        while (reader.Read())
        //        {
        //            if (reader.NodeType == XmlNodeType.Element &&
        //                reader.Name == "SceneNode")
        //                info = new SubImageInfo();
        //            else if (reader.NodeType == XmlNodeType.Element &&
        //                reader.Name == "ZOrder")
        //                info.Index = reader.ReadElementContentAsInt();
        //            else if (reader.NodeType == XmlNodeType.Element &&
        //                reader.Name == "FileName")
        //            {
        //                info.Caption = reader.ReadInnerXml();
        //            }
        //            else if (reader.NodeType == XmlNodeType.Element &&
        //                reader.Name == "Tag")
        //            {
        //                string[] substrings =
        //                    reader.ReadElementContentAsString().Split('+');
        //                info.Caption = substrings[0];
        //                if (substrings.Length > 1)
        //                    info.Description = substrings[1];
        //                else
        //                    info.Description = String.Empty;
        //            }
        //            else if (reader.NodeType == XmlNodeType.EndElement &&
        //                reader.Name == "SceneNode")
        //                images.Add(info);
        //        }
        //    }
        //    catch (XmlException)
        //    {
        //        MessageBox.Show("Error parsing XML metadata ");
        //    }

        //    _Metadata = new SubImageInfo[images.Count];

        //    foreach (SubImageInfo image in images)
        //        _Metadata[image.Index] = image;
        //}

        #endregion

    }

    public class SubImageInfo
    {
        public string Caption { get; set; }
        public string Description { get; set; }
        public int Index { get; set; }
    }

    public class MandelbrotTileSource : MultiScaleTileSource
    {

        private int _width;  // Tile width
        private int _height; // Tile height

        public MandelbrotTileSource(int imageWidth, int imageHeight, int tileWidth, int tileHeight) :
            base(imageWidth, imageHeight, tileWidth, tileHeight, 0)
        {
            _width = tileWidth;
            _height = tileHeight;
        }

        protected override void GetTileLayers(int level, int posx, int posy, IList<object> sources)
        {
            sources.Add(new Uri(App._SelFileName, UriKind.Absolute));
        }

    }

}


